using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using uTILLIty.Rave.Contract.Configuration;
using uTILLIty.Rave.Contract.StorageAdapter;

#pragma warning disable 612,618
namespace uTILLIty.Rave.Core.Strategy
{
	[TestClass]
	public class DefaultConfigurationApplicatorStrategyTests : TestBase
	{
		private readonly string _rightRwx = (FileSystemRights.Read | FileSystemRights.Write | FileSystemRights.ExecuteFile).ToString();
		private readonly string _rightR = (FileSystemRights.Read).ToString();
		private readonly string _rightF = (FileSystemRights.FullControl).ToString();

		[TestMethod, DeploymentItem("Samples\\ConfigurationApplicator.xml")]
		public void ProcessSecurityNewOnly()
		{
			var target = new DefaultConfigurationApplicatorStrategy();
			var context = CreateUnitTestContext();
			target.ApplicatorContext = context;
			var di = new DirectoryContext(context.Configuration.Directories[0], null);

			var existingEntries = new List<SecurityEntryContext>(4)
                              {
                                CreateSecurityEntryContext(AdminsStorageMember, _rightRwx, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(UsersStorageMember, _rightR, new SecurityEntry(MemberType.Group)),
                                CreateSecurityEntryContext(JohnStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(SystemStorageMember, _rightRwx, new SecurityEntry(MemberType.User)),
                              };
			//http://hibernatingrhinos.com/open-source/rhino-mocks
			bool containsInheritedAcls;
			StorageAdapter.Stub(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls)).Return(existingEntries);

			target.ProcessSecurity(di);

			StorageAdapter.AssertWasCalled(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls));
			StorageAdapter.AssertWasCalled(s => s.ApplySecurityChanges(null, null), c => c.IgnoreArguments());
			Assert.AreEqual(5, existingEntries.Count);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, AdminsStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, UsersStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, JohnStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, SystemStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Add, existingEntries.Single(e => Equals(e.StorageMember, MikeStorageMember)).Action);
		}

		[TestMethod, DeploymentItem("Samples\\ConfigurationApplicator.xml")]
		public void ProcessSecurityDeleteOnly()
		{
			var target = new DefaultConfigurationApplicatorStrategy();
			var context = CreateUnitTestContext();
			context.Configuration.Directories[0].SecurityEntries =
				context.Configuration.Directories[0].SecurityEntries.Where(se => se.MemberID != "Mike").ToArray();
			target.ApplicatorContext = context;
			var di = new DirectoryContext(context.Configuration.Directories[0], null);

			var existingEntries = new List<SecurityEntryContext>(4)
                              {
                                CreateSecurityEntryContext(AdminsStorageMember, _rightRwx, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(UsersStorageMember, _rightR, new SecurityEntry(MemberType.Group)),
                                CreateSecurityEntryContext(JohnStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(SystemStorageMember, _rightRwx, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(MikeStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                              };
			//http://hibernatingrhinos.com/open-source/rhino-mocks
			bool containsInheritedAcls;
			StorageAdapter.Stub(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls)).Return(existingEntries);

			target.ProcessSecurity(di);

			StorageAdapter.AssertWasCalled(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls));
			StorageAdapter.AssertWasCalled(s => s.ApplySecurityChanges(null, null), c => c.IgnoreArguments());
			Assert.AreEqual(5, existingEntries.Count);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, AdminsStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, UsersStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, JohnStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, SystemStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Remove, existingEntries.Single(e => Equals(e.StorageMember, MikeStorageMember)).Action);
		}

		[TestMethod, DeploymentItem("Samples\\ConfigurationApplicator.xml")]
		public void ProcessSecurityChangeOnly()
		{
			var target = new DefaultConfigurationApplicatorStrategy();
			var context = CreateUnitTestContext();
			target.ApplicatorContext = context;
			var di = new DirectoryContext(context.Configuration.Directories[0], null);

			var existingEntries = new List<SecurityEntryContext>(4)
                              {
                                CreateSecurityEntryContext(AdminsStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(UsersStorageMember, _rightR, new SecurityEntry(MemberType.Group)),
                                CreateSecurityEntryContext(JohnStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(SystemStorageMember, _rightRwx, new SecurityEntry(MemberType.User)),
                                CreateSecurityEntryContext(MikeStorageMember, _rightF, new SecurityEntry(MemberType.User)),
                              };
			//http://hibernatingrhinos.com/open-source/rhino-mocks
			bool containsInheritedAcls;
			StorageAdapter.Stub(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls)).Return(existingEntries);

			target.ProcessSecurity(di);

			StorageAdapter.AssertWasCalled(s => s.GetExistingSecurityEntries(di, out containsInheritedAcls));
			StorageAdapter.AssertWasCalled(s => s.ApplySecurityChanges(null, null), c => c.IgnoreArguments());
			Assert.AreEqual(5, existingEntries.Count);
			Assert.AreEqual(SecurityEntryAction.Update, existingEntries.Single(e => Equals(e.StorageMember, AdminsStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, UsersStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, JohnStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, SystemStorageMember)).Action);
			Assert.AreEqual(SecurityEntryAction.Nothing, existingEntries.Single(e => Equals(e.StorageMember, MikeStorageMember)).Action);
		}

		private SecurityEntryContext CreateSecurityEntryContext(StorageMember member, string rights, SecurityEntry securityEntry)
		{
			var ctx = new SecurityEntryContext(member, rights) { TemplateSecurityEntry = securityEntry };
			ctx.TemplateSecurityEntry.Rights = rights;
			return ctx;
		}
	}
}
#pragma warning restore 612,618
